#!/usr/bin/python2.4
#
# A library for interacting with Sirus Satellite Internet Radio streams
#
# Copyright 2008 jeff@rebeiro.net (Jeffrey M. Rebeiro)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import cookielib
import md5
import re
import urllib
import urllib2


class Sirius:

  def __init__(self, username, password):
    self.username = username
    self.password = md5.new(password).hexdigest()
    self.login_type = 'subscriber'
    self.login_params = None
    self.captcha_id = None
    self.captcha_response = None
    self.token = None
    self.category_name = None
    self.genre_name = None
    self.channel_data = None
    self.req_data = None
    self.req_headers = {'User-Agent': 'Mozilla/5.0 '
                                      '(X11; U; Linux i686; en-US; rv:1.9.0.3) '
                                      'Gecko/2008092416 Firefox/3.0.3'}
    self.__CreateCookieJar()

  def __CreateCookieJar(self):
    cj = cookielib.CookieJar()
    opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
    urllib2.install_opener(opener)

  def GetCategoryList(self):
    url = 'http://www.sirius.com/sirius/mediaplayer/player/common/lineup/' \
            'category.jsp?category=&genre=&channel='
    req = urllib2.Request(url, self.req_data, self.req_headers)
    categories_html = urllib2.urlopen(req).read()
    category_regex = r'javascript:myPlayer\.Category\(\'(.*)\','
    categories = re.findall(category_regex, categories_html)
    return categories

  def SetCategory(self, category_name):
    self.category_name = category_name
    self.genre_name = None
    self.channel_data = None

  def GetGenreList(self):
    if not self.category_name:
      return

    url = 'http://www.sirius.com/sirius/mediaplayer/player/common/lineup/' \
            'genre.jsp?category=%s' % self.category_name
    req = urllib2.Request(url, self.req_data, self.req_headers)
    genres_html = urllib2.urlopen(req).read()
    genre_regex = r'javascript:myPlayer\.Genre\(\'.*\', \'(.*)\',\''
    genres = re.findall(genre_regex, genres_html)
    return genres

  def SetGenre(self, genre_name):
    self.genre_name = genre_name
    self.channel_data = None

  def GetChannelList(self):
    if not self.category_name or not self.genre_name:
      return

    url = 'http://www.sirius.com/sirius/mediaplayer/player/common/lineup/' \
            'channel.jsp?category=%s&genre=%s' % (self.category_name,
                                                  self.genre_name)
    req = urllib2.Request(url, self.req_data, self.req_headers)
    channels_html = urllib2.urlopen(req).read()
    channel_regex = (r'<a href="javascript:myPlayer\.Channel\(\'.*\', \'.*\', '
                     '\'(?P<channel>.*)\',\'.*\', \'(?P<token>.*)\'\)" class='
                     '"channel">(?P<number>\d+).*</a>\r\n.*<a href="javascript'
                     ':myPlayer\.Channel\(\'.*\', \'.*\', \'.*\',\'.*\', \'.*'
                     '\'\)" class="text">(?P<text>.*)</a>\r\n.*<a href="'
                     'javascript:myPlayer\.Channel\(\'.*\', \'.*\', \'.*\','
                     '\'.*\', \'.*\'\)" class="desc">(?P<description>.*)</a>')
    channels = []
    for m in re.finditer(channel_regex, channels_html):
      channels.append(m.groupdict())

    return channels

  def SetChannel(self, channel_data):
    self.channel_data = channel_data

  def GetChannel(self):
    return self.channel_data

  def GetChannelURL(self):
    """Retrieves the URL for the channel set by self.SetChannel().

    Returns:
      A string containing a URL or nothing if channel is not set
    """
    if not self.channel_data:
      return

    url = 'http://www.sirius.com/sirius/servlet/MediaPlayer?' \
            'activity=selectStream&stream=%s&token=%s' % \
            (self.channel_data['channel'], self.channel_data['token'])
    req = urllib2.Request(url, self.req_data, self.req_headers)
    channel_html = urllib2.urlopen(req).read()
    url_regex = r'<PARAM NAME="FileName" VALUE="(?P<stream_url>.*)">'
    m = re.search(url_regex, channel_html)
    return m.group(1)

  def GetToken(self, login_html):
    """Retrieves the token from the Sirius Player login page.

    Args:
      login_html: output from urllib2.urlopen().read()

    Returns:
      Nothing
    """
    token_regex = r'<input type="hidden" name="token" value="(?P<token>.*)">'
    m = re.search(token_regex, login_html)
    self.token = m.groupdict()['token']

  def GetCaptchaID(self, login_html):
    """Retrieves the captcha ID from the Sirius Player login page.

    Args:
      login_html: output from urllib2.urlopen().read()

    Returns:
      Nothing
    """
    captcha_id_regex = (r'<input type="hidden" name="captchaID" value="'
                        '(?P<captcha_id>.*)">')
    m = re.search(captcha_id_regex, login_html)
    self.captcha_id = m.groupdict()['captcha_id']

  def GetCaptchaResponse(self, login_html):
    """Decodes Sirius captcha codes based on a static index.

    Args:
      login_html: output from urllib2.urlopen().read()

    Returns:
      Nothing
    """
    captcha_image_regex = (r'<img src="/mp/captcha/image/img_'
                           '(?P<captcha_image>\d+).jpg')
    m = re.search(captcha_image_regex, login_html)
    img_index = int(m.groupdict()['captcha_image']) - 1

    captcha_codes = ['wrQ2','LtFK','2bxh','Mf6D','fEXY','Wc46','fYP7','X6aw',
                     'nQQd','rt3k','kQhf','f2WG','aTLX','Qnaf','cA2T','cY36',
                     'xddQ','yaYf','4P67','7ekW','yZLN','RhLd','4eAC','bHKA',
                     't4kW','AZQE','RWhN','7rPD','fYWP','7HCb','aR3L','TDkT',
                     'kf4Y','yfFZ','eyDh','yWnK','NFWm','2n4d','634t','YnAH',
                     'MHPQ','N26M','Ra4C','dR4e','P6CZ','cnaW','W6wm','Wm3y',
                     'mrdG','3KhR','p6fY','AGen','ctDC','HDZY','WNKM','K72H',
                     'k627','PMW2','mEew','y3YA','r67T','nDpE','Q7MQ','kLW2',
                     'pyDR','AQkH','wdfW','eWQh','ttEP','tn6r','P6yx','nRKW',
                     'eXEb','ywNZ','MHZt','f7mc','RyMY','MTPC','rc3k','Xebn',
                     'ffGH','6Y2D','mbKX','6nCH','tHyG','RtAE','hWE2','3F6D',
                     'dQpC','HACn','Ampy','mLEr','Mdt2','QGbL','PDQp','EEyC',
                     'MfmL','PQ3f','HPPc','pTXc']

    self.captcha_response = captcha_codes[img_index]

  def Login(self):
    url = 'http://www.sirius.com/sirius/servlet/MediaPlayer'
    req = urllib2.Request(url, self.req_data, self.req_headers)
    login_data = urllib2.urlopen(req).read()
    self.GetToken(login_data)
    self.GetCaptchaID(login_data)
    self.GetCaptchaResponse(login_data)
    self.login_params = {'activity': 'login',
                         'token': self.token,
                         'username': self.username,
                         'captchaID': self.captcha_id,
                         'captcha_response': self.captcha_response,
                         'stream': 'undefined'}
    if self.login_type == 'subscriber':
      subscriber_params = {'password': self.password,
                           'type': 'subscriber',
                           'loginForm': 'subscriber'}
      self.login_params.update(subscriber_params)
    elif self.login_type == 'guest':
      guest_params = {'type': 'guest',
                      'encryptedPassword': self.password,
                      'loginForm': 'guest'}
      self.login_params.update(guest_params)
    params = urllib.urlencode(self.login_params)
    url = 'http://www.sirius.com/sirius/servlet/MediaPlayerLogin/subscriber'
    req = urllib2.Request(url, self.req_data, self.req_headers)
    response = urllib2.urlopen(req, params)
    if(response.read().find('redirect to player') != -1):
      return True
    else:
      return False

  def GetSongInfo(self):
    """Get the current song information from DogstarRadio.

    Returns:
      dict:
        'artist': Artist Name
        'title': Song Title
    """
    dogstar_url = ('http://www.dogstarradio.com/channelrss/%s.txt' %
                   self.channel_data['number'])
    tracker = urllib2.urlopen(dogstar_url).read()
    song_info = {}
    lines = tracker.split("\n")
    song_info['artist'] = lines[3]
    song_info['title'] = lines[4]

    return song_info

